﻿using System;
using System.Collections;
using System.Text;
using Microsoft.SPOT.IO;
using System.IO;

namespace mfLogger
{
    /// <summary>
    /// represents an always date-sorted list of messages
    /// </summary>
    /// <remarks>implemented with two indices, an outer-time-based index and an inner position-based-index</remarks>
    public class mfLogMessageCollection
    {
        #region Fields

        ArrayList _msgList = null;

        const int C_INT_START_INDEX = -1;
        int _innerIndex = C_INT_START_INDEX;

        #endregion

        #region CTOR

        public mfLogMessageCollection(int capacity)
            : base()
        {
            _msgList = new ArrayList();
            _msgList.Capacity = capacity + 1;//+1 -->to avoid auto memory allocation

            ResetInnerIndex();
        }

        #endregion

        #region inner index calculations
        bool _isFilledOnce = false;
        private void ResetInnerIndex()
        {
            _innerIndex = C_INT_START_INDEX;
        }

        private int IncrementInnerIndex()
        {
            if ((_innerIndex + 1) >= (_msgList.Capacity - 1))
            {
                ResetInnerIndex();
                _isFilledOnce = true;
            }

            return _innerIndex++;
        }

        private int CalculateInnerIndex(int outerIndex)
        {
            var cap = _msgList.Capacity - 1;
            if (_isFilledOnce)
            {
                outerIndex += _innerIndex + 1;
            }
            return outerIndex % cap;
        }

        private int CalculateOuterIndex(int innerIndex)
        {
            //sample (innerIndex = 1):  abs(10 - (10 - 1) % 10) = 1
            var cap = _msgList.Capacity - 1;
            return Math.Abs((cap - (cap - _innerIndex)) % cap);
        }
        #endregion

        private mfLogMessage AssertIfTypeIsInvalid(mfLogMessage value)
        {
            var logger = value as mfLogMessage;

            if (logger == null)
                throw new mfLoggerException(GetType() + ": value '" + value.ToString() + "' is no valid object from type 'Message'");

            return logger;
        }

        public int Capacity
        {
            get
            {
                return _msgList.Capacity;
            }
            set
            {
                _msgList.Clear();
                ResetInnerIndex();
                _msgList.Capacity = value;
            }
        }

        public int Count
        {
            get
            {
                return _msgList.Count;
            }
        }

        public new mfLogMessage this[int index]
        {
            get
            {
                var innerIndex = CalculateInnerIndex(index);
                return _msgList[innerIndex] as mfLogMessage;
            }
            set
            {
                var logger = AssertIfTypeIsInvalid(value);

                var innerIndex = CalculateInnerIndex(index);
                _msgList[innerIndex] = logger;
            }
        }

        public int Add(mfLogMessage value)
        {
            var logger = AssertIfTypeIsInvalid(value);

            IncrementInnerIndex();

            //if (_msgList.Count == (_msgList.Capacity -1))
            if (_isFilledOnce)
            {
                _msgList[_innerIndex] = value;
            }
            else//for first fullfill
            {
                _msgList.Insert(_innerIndex, value);
            }

            return CalculateOuterIndex(_innerIndex);
        }

        public void RemoveAt(int index)
        {
            var innerIndex = CalculateInnerIndex(index);
            mfLogMessage msg = _msgList[innerIndex] as mfLogMessage;

            _msgList.RemoveAt(innerIndex);
            
            if (msg != null) msg.Dispose();
        }

        public bool Contains(mfLogMessage item)
        {
            var logger = AssertIfTypeIsInvalid(item);

            return _msgList.Contains(logger);
        }

        public int IndexOf(mfLogMessage value)
        {
            var logger = AssertIfTypeIsInvalid(value);

            return CalculateOuterIndex(_msgList.IndexOf(logger));
        }

        public void Clear()
        {
            _msgList.Clear();
            ResetInnerIndex();
        }

    }
}
